import re
from string import lower
from ysna.auth.models import User, AbstractUser, Student, Teacher, Institute
from django.shortcuts import render_to_response
from django.template import RequestContext
from ysna.myprofile.views import getUser

'''
author: Nader
date: 18.2.12
desc: Searches for everything
params: HttpRequest
GETparams: string query
'''
def search(request):
    query = request.GET['query'] 
    category = request.GET['category']
       
    if re.match(r'^\".*\"$', query) or re.match(r'^\'.*\'$', query): # Search for exact query
        if re.match(r'^\".*\"$', query): #remove the double quotations
            query = re.sub("^\"(.*)\"$", r'''\1''', query)
        else: #remove the single quotations
            query = re.sub("^\'(.*)\'$", r'''\1''', query)
        
        # Start search
        if not lower(query).__contains__("or"): # Search for exact query, all ANDed
            [students, teachers, institutes, t_experience, s_experience,
             t_favourite_genre, s_favourite_genre, t_instrument_played,
             s_instrument_played, t_jamming_style, s_jamming_style, teaches] = searchExact(query)
        else: # Search for exact query, part ORed, part ANDed
            if re.match(r'^.+\s.+\sor\s.+\s.+', query): # e.g. Nader Joseph or Saady Alexan
                first = re.sub(r'^(.+)\s(.+)\sor\s(.+)\s(.+)', r'''\1''', query)
                second = re.sub(r'^(.+)\s(.+)\sor\s(.+)\s(.+)', r'''\2''', query)
                third = re.sub(r'^(.+)\s(.+)\sor\s(.+)\s(.+)', r'''\3''', query)
                fourth = re.sub(r'^(.+)\s(.+)\sor\s(.+)\s(.+)', r'''\4''', query)
            elif re.match(r'^.+\s.+\sor\s.+$', query): # e.g. Nader Joseph or Saady
                first = re.sub(r'^(.+)\s(.+)\sor\s(.+)$', r'''\1''', query)
                second = re.sub(r'^(.+)\s(.+)\sor\s(.+)$', r'''\2''', query)
                third = re.sub(r'^(.+)\s(.+)\sor\s(.+)$', r'''\3''', query)
                fourth = ""
            elif re.match(r'^.+\sor\s.+\s.+', query):# e.g. Joseph or Saady Alexan
                first = ""
                second = re.sub(r'^(.+)\sor\s(.+)\s(.+)', r'''\1''', query)
                third = re.sub(r'^(.+)\sor\s(.+)\s(.+)', r'''\2''', query)
                fourth = re.sub(r'^(.+)\sor\s(.+)\s(.+)', r'''\3''', query)   
            else: # e.g. Joseph or Saady
                first = ""
                second = re.sub(r'^(.+)\sor\s(.+)$', r'''\1''', query)
                third = re.sub(r'^(.+)\sor\s(.+)$', r'''\2''', query)
                fourth = ""
            
            [students_1_4, teachers_1_4, institutes_1_4, t_experience_1_4, s_experience_1_4,
             t_favourite_genre_1_4, s_favourite_genre_1_4, t_instrument_played_1_4,
             s_instrument_played_1_4, t_jamming_style_1_4, s_jamming_style_1_4, teaches_1_4] = searchExact(first + " " + fourth)
            
            #OR the second and third
            [students_2_3, teachers_2_3, institutes_2_3, t_experience_2_3, s_experience_2_3,
             t_favourite_genre_2_3, s_favourite_genre_2_3, t_instrument_played_2_3,
             s_instrument_played_2_3, t_jamming_style_2_3, s_jamming_style_2_3, teaches_2_3] = searchORexact(second, third)
             
            [students, teachers, institutes, t_experience, s_experience,
              t_favourite_genre, s_favourite_genre, t_instrument_played,
              s_instrument_played, t_jamming_style, s_jamming_style, teaches] = [(students_1_4 & students_2_3) | (students_2_3 & students_1_4),
                                                                                 (teachers_1_4 & teachers_2_3) | (teachers_2_3 & teachers_1_4),
                                                                                 (institutes_1_4 & institutes_2_3) | (institutes_2_3 & institutes_1_4),
                                                                                 (t_experience_1_4 & t_experience_2_3) | (t_experience_2_3 & t_experience_1_4),
                                                                                 (s_experience_1_4 & s_experience_2_3) | (s_experience_2_3 & s_experience_1_4),
                                                                                 (t_favourite_genre_1_4 & t_favourite_genre_2_3) | (t_favourite_genre_2_3 & t_favourite_genre_1_4),
                                                                                 (s_favourite_genre_1_4 & s_favourite_genre_2_3) | (s_favourite_genre_2_3 & s_favourite_genre_1_4),
                                                                                 (t_instrument_played_1_4 & t_instrument_played_2_3) | (t_instrument_played_2_3 & t_instrument_played_1_4),
                                                                                 (s_instrument_played_1_4 & s_instrument_played_2_3) | (s_instrument_played_2_3 & s_instrument_played_1_4),
                                                                                 (t_jamming_style_1_4 & t_jamming_style_2_3) | (t_jamming_style_2_3 & t_jamming_style_1_4),
                                                                                 (s_jamming_style_1_4 & s_jamming_style_2_3) | (s_jamming_style_2_3 & s_jamming_style_1_4),
                                                                                 (teaches_2_3 & teaches_1_4) | (teaches_1_4 & teaches_2_3)]
        
    else: # Search for icontains query
        if not lower(query).__contains__("or"): # Search for icontains query, all ANDed
            # Get search results for icontains arguments
            [students, teachers, institutes, t_experience, s_experience,
             t_favourite_genre, s_favourite_genre, t_instrument_played,
             s_instrument_played, t_jamming_style, s_jamming_style, teaches] = searchIContains(query)
        else: # Search for icontains query, part ANDed, part ORed
            if re.match(r'^.+\s.+\sor\s.+\s.+', query): # e.g. Nader Joseph or Saady Alexan
                first = re.sub(r'^(.+)\s(.+)\sor\s(.+)\s(.+)', r'''\1''', query)
                second = re.sub(r'^(.+)\s(.+)\sor\s(.+)\s(.+)', r'''\2''', query)
                third = re.sub(r'^(.+)\s(.+)\sor\s(.+)\s(.+)', r'''\3''', query)
                fourth = re.sub(r'^(.+)\s(.+)\sor\s(.+)\s(.+)', r'''\4''', query)
            elif re.match(r'^.+\s.+\sor\s.+$', query): # e.g. Nader Joseph or Saady
                first = re.sub(r'^(.+)\s(.+)\sor\s(.+)$', r'''\1''', query)
                second = re.sub(r'^(.+)\s(.+)\sor\s(.+)$', r'''\2''', query)
                third = re.sub(r'^(.+)\s(.+)\sor\s(.+)$', r'''\3''', query)
                fourth = ""
            elif re.match(r'^.+\sor\s.+\s.+', query):# e.g. Joseph or Saady Alexan
                first = ""
                second = re.sub(r'^(.+)\sor\s(.+)\s(.+)', r'''\1''', query)
                third = re.sub(r'^(.+)\sor\s(.+)\s(.+)', r'''\2''', query)
                fourth = re.sub(r'^(.+)\sor\s(.+)\s(.+)', r'''\3''', query)   
            else: # e.g. Joseph or Saady
                first = ""
                second = re.sub(r'^(.+)\sor\s(.+)$', r'''\1''', query)
                third = re.sub(r'^(.+)\sor\s(.+)$', r'''\2''', query)
                fourth = ""
                
            [students_1_4, teachers_1_4, institutes_1_4, t_experience_1_4, s_experience_1_4,
             t_favourite_genre_1_4, s_favourite_genre_1_4, t_instrument_played_1_4,
             s_instrument_played_1_4, t_jamming_style_1_4, s_jamming_style_1_4, teaches_1_4] = searchIContains(first + " " + fourth)
            
            #OR the second and third
            [students_2_3, teachers_2_3, institutes_2_3, t_experience_2_3, s_experience_2_3,
             t_favourite_genre_2_3, s_favourite_genre_2_3, t_instrument_played_2_3,
             s_instrument_played_2_3, t_jamming_style_2_3, s_jamming_style_2_3, teaches_2_3] = searchORicontains(second, third)
             
            [students, teachers, institutes, t_experience, s_experience,
              t_favourite_genre, s_favourite_genre, t_instrument_played,
              s_instrument_played, t_jamming_style, s_jamming_style, teaches] = [(students_1_4 & students_2_3) | (students_2_3 & students_1_4),
                                                                                 (teachers_1_4 & teachers_2_3) | (teachers_2_3 & teachers_1_4),
                                                                                 (institutes_1_4 & institutes_2_3) | (institutes_2_3 & institutes_1_4),
                                                                                 (t_experience_1_4 & t_experience_2_3) | (t_experience_2_3 & t_experience_1_4),
                                                                                 (s_experience_1_4 & s_experience_2_3) | (s_experience_2_3 & s_experience_1_4),
                                                                                 (t_favourite_genre_1_4 & t_favourite_genre_2_3) | (t_favourite_genre_2_3 & t_favourite_genre_1_4),
                                                                                 (s_favourite_genre_1_4 & s_favourite_genre_2_3) | (s_favourite_genre_2_3 & s_favourite_genre_1_4),
                                                                                 (t_instrument_played_1_4 & t_instrument_played_2_3) | (t_instrument_played_2_3 & t_instrument_played_1_4),
                                                                                 (s_instrument_played_1_4 & s_instrument_played_2_3) | (s_instrument_played_2_3 & s_instrument_played_1_4),
                                                                                 (t_jamming_style_1_4 & t_jamming_style_2_3) | (t_jamming_style_2_3 & t_jamming_style_1_4),
                                                                                 (s_jamming_style_1_4 & s_jamming_style_2_3) | (s_jamming_style_2_3 & s_jamming_style_1_4),
                                                                                 (teaches_2_3 & teaches_1_4) | (teaches_1_4 & teaches_2_3)]
    
    loggedIn = request.user.is_authenticated()
    
    empty = True
    if category == 'all':
        if students or teachers or institutes or t_experience or s_experience or t_favourite_genre or s_favourite_genre or t_instrument_played or s_instrument_played or t_jamming_style or s_jamming_style or teaches:
            empty = False
    elif category == 'students': 
        if students: empty = False
    elif category == 'teachers':
        if teachers: empty = False
    elif category == 'institutes':
        if institutes: empty = False
    elif category == 'experience':
        if t_experience or s_experience: empty = False
    elif category == 'favourite_genre':
        if t_favourite_genre or s_favourite_genre: empty = False
    elif category == 'instrument_played':
        if t_instrument_played or s_instrument_played: empty = False
    elif category == 'jamming_style':
        if t_jamming_style or s_jamming_style: empty = False
    elif category == 'teaches':
        if teaches: empty = False
    else:
        print category

    loggedInUser = currentUser = getUser(request.user, abstract=False)
    profileOwner = True
    
    return render_to_response('searchresults.html', {'loggedInUser':loggedInUser, 'currentUser':currentUser, 'profileOwner':profileOwner,
                                                     'category':category, 'students':students, 'teachers':teachers, 'institutes':institutes,
                                                     't_experience':t_experience, 's_experience':s_experience,
                                                     't_favourite_genre':t_favourite_genre, 's_favourite_genre':s_favourite_genre,
                                                     't_instrument_played':t_instrument_played, 's_instrument_played':s_instrument_played,
                                                     't_jamming_style':t_jamming_style, 's_jamming_style':s_jamming_style,
                                                     'teaches':teaches, 'query':query, 'loggedIn':loggedIn, 'empty':empty}, context_instance=RequestContext(request))
    
def searchExact(query):
    if query == " " or not query or query == '':
        return [Student.objects.all(), Teacher.objects.all(), Institute.objects.all(),
                Teacher.objects.all(), Student.objects.all(), Teacher.objects.all(),
                Student.objects.all(), Teacher.objects.all(), Student.objects.all(),
                Teacher.objects.all(), Student.objects.all(), Teacher.objects.all()]
    
    #Initially all objects are considered results, until we narrow down
    users = User.objects.all()
    #abstract_user = AbstractUser.objects.all()
    #students, teachers, institutes = Student.objects.all(), Teacher.objects.all(), Institute.objects.all()
    t_experience, s_experience = Teacher.objects.all(), Student.objects.all() 
    t_favourite_genre, s_favourite_genre = Teacher.objects.all(), Student.objects.all() 
    t_instrument_played, s_instrument_played = Teacher.objects.all(), Student.objects.all()
    t_jamming_style, s_jamming_style = Teacher.objects.all(), Student.objects.all()
    teaches = Teacher.objects.all()
    
    queryArr = query.split(" ") #Split words in the query    
    for ele in queryArr:#Loop through the elements and AND them
        if ele == "":
            continue
        '''
        USERS
        '''
        #USER attributes searched
        users &= (User.objects.filter(username__exact=ele) | User.objects.filter(email__exact=ele) | User.objects.filter(first_name__exact=ele) | User.objects.filter(last_name__exact=ele))
        
        '''
        USER ATTRIBUTE
        '''
        #Experience
        t_experience &= Teacher.objects.filter(experience__exact=ele)
        s_experience &= Student.objects.filter(experience__exact=ele)
        #Favourite_genre
        t_favourite_genre &= Teacher.objects.filter(favourite_genre__exact=ele)
        s_favourite_genre &= Student.objects.filter(favourite_genre__exact=ele)
        #Instrument_played
        t_instrument_played &= Teacher.objects.filter(instrument_played__exact=ele)
        s_instrument_played &= Student.objects.filter(instrument_played__exact=ele)
        #Jamming_style
        t_jamming_style &= Teacher.objects.filter(jamming_style__exact=ele)
        s_jamming_style &= Student.objects.filter(jamming_style__exact=ele)
        #Teaches
        teaches &= Teacher.objects.filter(teaches__exact=ele)
    
    #Get abstract users
    abstract_user = AbstractUser.objects.filter(user=users)
    for u in users:
        abstract_user |= AbstractUser.objects.filter(user=u)
    
    students = Student.objects.filter(abstract_user=abstract_user)
    teachers = Teacher.objects.filter(abstract_user=abstract_user)
    institutes = Institute.objects.filter(abstract_user=abstract_user)
    for au in abstract_user:
        #Get Students
        students |= Student.objects.filter(abstract_user=au)
        #Get Teachers
        teachers |= Teacher.objects.filter(abstract_user=au)
        #Get Institutes
        institutes |= Institute.objects.filter(abstract_user=au)
    
    return [students, teachers, institutes, t_experience, s_experience,
            t_favourite_genre, s_favourite_genre, t_instrument_played,
            s_instrument_played, t_jamming_style, s_jamming_style, teaches]

def searchIContains(query):
    
    if query == " " or not query or query == '':
        print'QUERY:', query
        return [Student.objects.all(), Teacher.objects.all(), Institute.objects.all(),
                Teacher.objects.all(), Student.objects.all(), Teacher.objects.all(),
                Student.objects.all(), Teacher.objects.all(), Student.objects.all(),
                Teacher.objects.all(), Student.objects.all(), Teacher.objects.all()]
    #Initially all objects are considered results, until we narrow down
    users = User.objects.all()
    #abstract_user = AbstractUser.objects.all()
    #students, teachers, institutes = Student.objects.all(), Teacher.objects.all(), Institute.objects.all()
    t_experience, s_experience = Teacher.objects.all(), Student.objects.all() 
    t_favourite_genre, s_favourite_genre = Teacher.objects.all(), Student.objects.all() 
    t_instrument_played, s_instrument_played = Teacher.objects.all(), Student.objects.all()
    t_jamming_style, s_jamming_style = Teacher.objects.all(), Student.objects.all()
    teaches = Teacher.objects.all()
    
    queryArr = query.split(" ") #Split words in the query
  
    for ele in queryArr:#Loop through the elements and AND them
        if ele == "":
            continue
        '''
        USERS
        '''
        #USER attributes searched
        users &= (User.objects.filter(username__icontains=ele) | \
                  User.objects.filter(email__icontains=ele) | \
                   User.objects.filter(first_name__icontains=ele) | \
                   User.objects.filter(last_name__icontains=ele))
        
        '''
        USER ATTRIBUTE
        '''
        #Experience
        t_experience &= Teacher.objects.filter(experience__icontains=ele)
        s_experience &= Student.objects.filter(experience__icontains=ele)
        #Favourite_genre
        t_favourite_genre &= Teacher.objects.filter(favourite_genre__icontains=ele)
        s_favourite_genre &= Student.objects.filter(favourite_genre__icontains=ele)
        #Instrument_played
        t_instrument_played &= Teacher.objects.filter(instrument_played__icontains=ele)
        s_instrument_played &= Student.objects.filter(instrument_played__icontains=ele)
        #Jamming_style
        t_jamming_style &= Teacher.objects.filter(jamming_style__icontains=ele)
        s_jamming_style &= Student.objects.filter(jamming_style__icontains=ele)
        #Teaches
        teaches &= Teacher.objects.filter(teaches__icontains=ele)
    
    
    #Get abstract users
    abstract_user = AbstractUser.objects.filter(user=users)
    for u in users:
        abstract_user |= AbstractUser.objects.filter(user=u)
    
    students = Student.objects.filter(abstract_user=abstract_user)
    teachers = Teacher.objects.filter(abstract_user=abstract_user)
    institutes = Institute.objects.filter(abstract_user=abstract_user)
    for au in abstract_user:
        #Get Students
        students |= Student.objects.filter(abstract_user=au)
        #Get Teachers
        teachers |= Teacher.objects.filter(abstract_user=au)
        #Get Institutes
        institutes |= Institute.objects.filter(abstract_user=au)
    
    return [students, teachers, institutes, t_experience, s_experience,
            t_favourite_genre, s_favourite_genre, t_instrument_played,
            s_instrument_played, t_jamming_style, s_jamming_style, teaches]

def searchORicontains(query1, query2):
    '''
    USERS
    '''
    #USER attributes searched
    users = User.objects.filter(username__icontains=query1) | User.objects.filter(email__icontains=query1) | \
             User.objects.filter(first_name__icontains=query1) | User.objects.filter(last_name__icontains=query1) | \
             User.objects.filter(username__icontains=query2) | User.objects.filter(email__icontains=query2) | \
             User.objects.filter(first_name__icontains=query2) | User.objects.filter(last_name__icontains=query2)
    
    #Get abstract users
    abstract_user = AbstractUser.objects.filter(user=users)
    for u in users:
        abstract_user |= AbstractUser.objects.filter(user=u)
    
    students = Student.objects.filter(abstract_user=abstract_user)
    teachers = Teacher.objects.filter(abstract_user=abstract_user)
    institutes = Institute.objects.filter(abstract_user=abstract_user)
    for au in abstract_user:
        #Get Students
        students |= Student.objects.filter(abstract_user=au)
        #Get Teachers
        teachers |= Teacher.objects.filter(abstract_user=au)
        #Get Institutes
        institutes |= Institute.objects.filter(abstract_user=au)
    '''
    USER ATTRIBUTE
    '''
    #Experience
    t_experience = Teacher.objects.filter(experience__icontains=query1) | Teacher.objects.filter(experience__icontains=query2)
    s_experience = Student.objects.filter(experience__icontains=query1) | Student.objects.filter(experience__icontains=query2) 
    #Favourite_genre
    t_favourite_genre = Teacher.objects.filter(favourite_genre__icontains=query1) | Teacher.objects.filter(favourite_genre__icontains=query2)
    s_favourite_genre = Student.objects.filter(favourite_genre__icontains=query1) | Student.objects.filter(favourite_genre__icontains=query2)
    #Instrument_played
    t_instrument_played = Teacher.objects.filter(instrument_played__icontains=query1) | Teacher.objects.filter(instrument_played__icontains=query2)
    s_instrument_played = Student.objects.filter(instrument_played__icontains=query1) | Student.objects.filter(instrument_played__icontains=query2)
    #Jamming_style
    t_jamming_style = Teacher.objects.filter(jamming_style__icontains=query1) | Teacher.objects.filter(jamming_style__icontains=query2)
    s_jamming_style = Student.objects.filter(jamming_style__icontains=query1) | Student.objects.filter(jamming_style__icontains=query2)
    #Teaches
    teaches = Teacher.objects.filter(teaches__icontains=query1) | Teacher.objects.filter(teaches__icontains=query2)

    return [students, teachers, institutes, t_experience, s_experience,
            t_favourite_genre, s_favourite_genre, t_instrument_played,
            s_instrument_played, t_jamming_style, s_jamming_style, teaches]

def searchORexact(query1, query2):
    '''
    USERS
    '''
    #USER attributes searched
    users = User.objects.filter(username__exact=query1) | User.objects.filter(email__exact=query1) | \
             User.objects.filter(first_name__exact=query1) | User.objects.filter(last_name__exact=query1) | \
             User.objects.filter(username__exact=query2) | User.objects.filter(email__exact=query2) | \
             User.objects.filter(first_name__exact=query2) | User.objects.filter(last_name__exact=query2)
    
    #Get abstract users
    abstract_user = AbstractUser.objects.filter(user=users)
    for u in users:
        abstract_user |= AbstractUser.objects.filter(user=u)
    
    students = Student.objects.filter(abstract_user=abstract_user)
    teachers = Teacher.objects.filter(abstract_user=abstract_user)
    institutes = Institute.objects.filter(abstract_user=abstract_user)
    for au in abstract_user:
        #Get Students
        students |= Student.objects.filter(abstract_user=au)
        #Get Teachers
        teachers |= Teacher.objects.filter(abstract_user=au)
        #Get Institutes
        institutes |= Institute.objects.filter(abstract_user=au)
    '''
    USER ATTRIBUTE
    '''
    #Experience
    t_experience = Teacher.objects.filter(experience__exact=query1) | Teacher.objects.filter(experience__exact=query2)
    s_experience = Student.objects.filter(experience__exact=query1) | Student.objects.filter(experience__exact=query2) 
    #Favourite_genre
    t_favourite_genre = Teacher.objects.filter(favourite_genre__exact=query1) | Teacher.objects.filter(favourite_genre__exact=query2)
    s_favourite_genre = Student.objects.filter(favourite_genre__exact=query1) | Student.objects.filter(favourite_genre__exact=query2)
    #Instrument_played
    t_instrument_played = Teacher.objects.filter(instrument_played__exact=query1) | Teacher.objects.filter(instrument_played__exact=query2)
    s_instrument_played = Student.objects.filter(instrument_played__exact=query1) | Student.objects.filter(instrument_played__exact=query2)
    #Jamming_style
    t_jamming_style = Teacher.objects.filter(jamming_style__exact=query1) | Teacher.objects.filter(jamming_style__exact=query2)
    s_jamming_style = Student.objects.filter(jamming_style__exact=query1) | Student.objects.filter(jamming_style__exact=query2)
    #Teaches
    teaches = Teacher.objects.filter(teaches__exact=query1) | Teacher.objects.filter(teaches__exact=query2)

    return [students, teachers, institutes, t_experience, s_experience,
            t_favourite_genre, s_favourite_genre, t_instrument_played,
            s_instrument_played, t_jamming_style, s_jamming_style, teaches]